package com.tsing.wms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.StyleSet;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tsing.wms.config.RedisManager;
import com.tsing.wms.constant.AuthConsts;
import com.tsing.wms.entity.*;
import com.tsing.wms.exception.CommonException;
import com.tsing.wms.exception.ServerException;
import com.tsing.wms.mapper.*;
import com.tsing.wms.service.IOutInRecordService;
import com.tsing.wms.util.GetLoginUserUtil;
import com.tsing.wms.valid.ValidList;
import com.tsing.wms.vo.PageResultVO;
import com.tsing.wms.vo.req.ExportRecordReqVO;
import com.tsing.wms.vo.req.IdReqVO;
import com.tsing.wms.vo.req.RecordPageReqVO;
import com.tsing.wms.vo.req.RecordReqVO;
import com.tsing.wms.vo.resp.IdAndNameRespVO;
import com.tsing.wms.vo.resp.RecordRespVO;
import com.tsing.wms.vo.resp.StockListRespVO;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 出入库记录表 服务实现类
 * </p>
 *
 * @author TheTsing
 * @since 2022-04-13
 */
@Service
public class OutInRecordServiceImpl extends ServiceImpl<OutInRecordMapper, OutInRecordEntity> implements IOutInRecordService {

    @Autowired
    private RedisManager redisManager;

    @Resource
    private StorehouseMapper storehouseMapper;

    @Resource
    private RecordDetailMapper recordDetailMapper;

    @Resource
    private StockMapper stockMapper;

    @Override
    public List<IdAndNameRespVO> storehouseList() {
        List<StorehouseEntity> storehouseEntities = storehouseMapper.selectList(null);
        return BeanUtil.copyToList(storehouseEntities, IdAndNameRespVO.class);
    }

    @Override
    public List<StockListRespVO> stockList(IdReqVO reqVO) {
        return baseMapper.stockList(reqVO.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addRecord(RecordReqVO reqVO, HttpServletRequest request) {
        if (GetLoginUserUtil.getLoginUserInfo(request.getHeader(AuthConsts.AUTHENTICATION_HEAD), redisManager).getIdentity() != 1) {
            throw new ServerException(CommonException.Proxy.AUTHORIZATION_EXCEPTION);
        }
        OutInRecordEntity outInRecordEntity = new OutInRecordEntity();
        BeanUtil.copyProperties(reqVO, outInRecordEntity);
        baseMapper.insert(outInRecordEntity);
        ValidList<RecordReqVO.RecordDetailReqVO> recordDetails = reqVO.getRecordDetails();
        recordDetails.forEach(item -> {
            recordDetailMapper.insert(new RecordDetailEntity()
                    .setOutRecordId(outInRecordEntity.getId())
                    .setGoodsId(item.getGoodsId())
                    .setAmount(item.getAmount()));
            StockEntity stockEntity = new LambdaQueryChainWrapper<>(stockMapper)
                    .select(StockEntity::getId, StockEntity::getAmount)
                    .eq(StockEntity::getGoodsId, item.getGoodsId())
                    .eq(StockEntity::getStorehouseId, reqVO.getStorehouseId())
                    .one();
            if (reqVO.getType() == 1) {
                //入库
                if (ObjectUtil.isNotNull(stockEntity)) {
                    //修改
                    stockMapper.updateById(stockEntity.setAmount(stockEntity.getAmount() + item.getAmount()));
                } else {
                    //添加
                    stockMapper.insert(new StockEntity()
                            .setGoodsId(item.getGoodsId())
                            .setStorehouseId(reqVO.getStorehouseId())
                            .setAmount(item.getAmount())
                    );
                }
            } else {
                //出库
                if (ObjectUtil.isNull(stockEntity) || stockEntity.getAmount() < item.getAmount()) {
                    throw new ServerException(CommonException.Proxy.OUT_RECORD_ERROR);
                }
                stockMapper.updateById(stockEntity.setAmount(stockEntity.getAmount() - item.getAmount()));
            }
        });
    }

    @Resource
    private UserMapper userMapper;

    @Override
    public RecordRespVO getRecord(IdReqVO reqVO) {
        OutInRecordEntity outInRecordEntity = baseMapper.selectById(reqVO.getId());
        RecordRespVO recordRespVO = new RecordRespVO();
        BeanUtil.copyProperties(outInRecordEntity, recordRespVO);
        UserEntity userEntity = new LambdaQueryChainWrapper<>(userMapper)
                .select(UserEntity::getUsername, UserEntity::getPhone)
                .eq(UserEntity::getId, recordRespVO.getUserId())
                .one();
        recordRespVO.setUserName(userEntity.getUsername());
        recordRespVO.setUserPhone(userEntity.getPhone());
        StorehouseEntity storehouseEntity = new LambdaQueryChainWrapper<>(storehouseMapper)
                .select(StorehouseEntity::getName, StorehouseEntity::getUserId)
                .eq(StorehouseEntity::getId, recordRespVO.getStorehouseId())
                .one();
        recordRespVO.setStorehouseName(storehouseEntity.getName());
        recordRespVO.setStorehousePhone(new LambdaQueryChainWrapper<>(userMapper)
                .select(UserEntity::getPhone)
                .eq(UserEntity::getId, storehouseEntity.getUserId())
                .one()
                .getPhone());
        recordRespVO.setRecordDetails(baseMapper.selectRecordDetails(recordRespVO.getId()));
        return recordRespVO;
    }

    @Override
    public PageResultVO<RecordRespVO> recordPage(RecordPageReqVO reqVO) {
        IPage<RecordRespVO> page = new Page<>(reqVO.getPageNum(), reqVO.getPageSize());
        baseMapper.recordPage(page, reqVO);
        page.getRecords().forEach(item -> {
            item.setGoodsTypeCount(new LambdaQueryChainWrapper<>(recordDetailMapper)
                    .select(RecordDetailEntity::getId)
                    .eq(RecordDetailEntity::getOutRecordId, item.getId())
                    .count());
            item.setGoodsCount(baseMapper.selectGoodsCount(item.getId()));
        });
        return new PageResultVO<>(page);
    }

    @Override
    public void exportRecord(ExportRecordReqVO reqVO, HttpServletRequest request, HttpServletResponse response) {
        RecordRespVO recordRespVO = getRecord(new IdReqVO().setId(reqVO.getId()));
        String fileName = (reqVO.getType() == 0 ? "出库单_" : "入库单_") + LocalDateTimeUtil.format(LocalDateTime.now(), "yyyyMMddHHmmssS") + ".xlsx";
        ExcelWriter writer = ExcelUtil.getWriter(true);
        setStyle(writer);

        writer.merge(0, 0, 0, 5,
                recordRespVO.getStorehouseName() + " - " + (reqVO.getType() == 0 ? "出库单" : "入库单") + DateUtil.format(recordRespVO.getCreateTime(), "yyyyMMddHHmmss"), true);
        writer.writeCellValue(0, 1, "订单编号：");
        setCellStyle(writer, 0, 1);
        writer.merge(1, 1, 1, 5, recordRespVO.getId(), false);

        writer.writeCellValue(0, 2, "仓库名称：");
        setCellStyle(writer, 0, 2);
        writer.writeCellValue(1, 2, recordRespVO.getStorehouseName());
        writer.writeCellValue(2, 2, "联系电话：");
        setCellStyle(writer, 2, 2);
        writer.writeCellValue(3, 2, recordRespVO.getStorehousePhone());
        writer.writeCellValue(4, 2, "入库时间：");
        setCellStyle(writer, 4, 2);
        writer.writeCellValue(5, 2, DateUtil.formatDateTime(recordRespVO.getCreateTime()));

        writer.writeCellValue(0, 3, "操作人：");
        setCellStyle(writer, 0, 3);
        writer.writeCellValue(1, 3, recordRespVO.getUserName());
        writer.writeCellValue(2, 3, "联系电话：");
        setCellStyle(writer, 2, 3);
        writer.writeCellValue(3, 3, recordRespVO.getUserPhone());
        writer.writeCellValue(4, 3, "");
        writer.writeCellValue(5, 3, "");
        int i = 4;
        writer.merge(i, i, 0, 1, "货物名称", false);
        setCellStyle(writer, 0, i);
        writer.merge(i, i, 2, 3, "规格", false);
        setCellStyle(writer, 2, i);
        writer.writeCellValue(4, i, "价格（元）");
        setCellStyle(writer, 4, i);
        writer.writeCellValue(5, i, "数量");
        setCellStyle(writer, 5, i);

        for (RecordRespVO.RecordDetailRespVO recordDetail : recordRespVO.getRecordDetails()) {
            i++;
            writer.merge(i, i, 0, 1, recordDetail.getGoodsName(), false);
            writer.merge(i, i, 2, 3, recordDetail.getSpecs(), false);
            writer.writeCellValue(4, i, recordDetail.getPrice());
            writer.writeCellValue(5, i, recordDetail.getAmount());
        }

        writer.writeCellValue(0, ++i, "备注：");
        setCellStyle(writer, 0, i);
        writer.merge(i, i, 1, 5, recordRespVO.getDescription(), false);

        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        try {
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            writer.flush(response.getOutputStream(), true);
        } catch (IOException e) {
        }
        writer.close();
    }

    private void setStyle(ExcelWriter writer) {
        StyleSet styleSet = writer.getStyleSet();
        // 设置标题样式
        CellStyle headCellStyle = styleSet.getHeadCellStyle();
        Font font = writer.createFont();
        font.setFontName("宋体");
        font.setBold(true);
        font.setFontHeightInPoints((short) 14);
        headCellStyle.setFont(font);
        // 背景颜色
        styleSet.setBackgroundColor(IndexedColors.WHITE, true);
        writer.setStyleSet(styleSet);
        writer.setColumnWidth(-1, 25);
        writer.setRowHeight(0, 30);
        writer.setDefaultRowHeight(25);
    }

    private void setCellStyle(ExcelWriter writer, int x, int y) {
        CellStyle cellStyle = writer.createCellStyle(x, y);
        Font font = writer.createFont();
        font.setBold(true);
        cellStyle.setFont(font);
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        cellStyle.setBorderTop(BorderStyle.THIN);
        cellStyle.setBorderBottom(BorderStyle.THIN);
        cellStyle.setBorderLeft(BorderStyle.THIN);
        cellStyle.setBorderRight(BorderStyle.THIN);
    }

}
